{{>partial_header}}
using System;
using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
{{#useSwashbuckle}}
using Microsoft.OpenApi.Models;
{{/useSwashbuckle}}
{{#useNewtonsoft}}
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
{{/useNewtonsoft}}
{{^useNewtonsoft}}
using System.Text.Json;
using System.Text.Json.Serialization;
{{/useNewtonsoft}}
using {{packageName}}.Authentication;
{{#useSwashbuckle}}
using {{packageName}}.Filters;
{{/useSwashbuckle}}
using {{packageName}}.OpenApi;
using {{packageName}}.Formatters;

namespace {{packageName}}
{
    /// <summary>
    /// Startup
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configuration"></param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// The application configuration.
        /// </summary>
        public IConfiguration Configuration { get; }

        /// <summary>
        /// This method gets called by the runtime. Use this method to add services to the container.
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
{{#authMethods}}
{{#isApiKey}}
            services.AddTransient<IAuthorizationHandler, ApiKeyRequirementHandler>();
            services.AddAuthorization(authConfig =>
            {
                authConfig.AddPolicy("{{name}}", policyBuilder =>
                {
                    policyBuilder
                        .AddRequirements(new ApiKeyRequirement(new[] { "my-secret-key" },"{{name}}"));
                });
            });
{{/isApiKey}}
{{/authMethods}}

            // Add framework services.
            services
                // Don't need the full MVC stack for an API, see https://andrewlock.net/comparing-startup-between-the-asp-net-core-3-templates/
                .AddControllers(options => {
                    options.InputFormatters.Insert(0, new InputFormatterStream());
                })
                {{#compatibilityVersion}}
                // Don't need this for 3.x - see https://docs.microsoft.com/en-us/aspnet/core/mvc/compatibility-version?view=aspnetcore-3.1
                //.SetCompatibilityVersion(CompatibilityVersion.{{.}})
                {{/compatibilityVersion}}
                {{#useNewtonsoft}}
                .AddNewtonsoftJson(opts =>
                {
                    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    opts.SerializerSettings.Converters.Add(new StringEnumConverter
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    });
                });
                {{/useNewtonsoft}}
                {{^useNewtonsoft}}
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
                    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
                });
                {{/useNewtonsoft}}
{{#useSwashbuckle}}
            services
                .AddSwaggerGen(c =>
                {
                    c.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
                    
                    c.SwaggerDoc("{{{version}}}{{^version}}v1{{/version}}", new OpenApiInfo
                    {
                        Title = "{{{appName}}}{{^appName}}{{packageName}}{{/appName}}",
                        Description = "{{{appName}}}{{^appName}}{{packageName}}{{/appName}} (ASP.NET Core {{aspnetCoreVersion}})",
                        TermsOfService = new Uri("{{{termsOfService}}}{{^termsOfService}}https://github.com/openapitools/openapi-generator{{/termsOfService}}"),
                        Contact = new OpenApiContact
                        {
                            Name = "{{{infoName}}}{{^infoName}}OpenAPI-Generator Contributors{{/infoName}}",
                            Url = new Uri("{{{infoUrl}}}{{^infoUrl}}https://github.com/openapitools/openapi-generator{{/infoUrl}}"),
                            Email = "{{{infoEmail}}}"
                        },
                        License = new OpenApiLicense
                        {
                            Name = "{{licenseName}}",
                            Url = new Uri("{{licenseUrl}}")
                        },
                        Version = "{{{version}}}{{^version}}v1{{/version}}",
                    });
                    c.CustomSchemaIds(type => type.FriendlyId(true));
                    c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{Assembly.GetExecutingAssembly().GetName().Name}.xml");
                    {{#basePathWithoutHost}}
                    // Sets the basePath property in the OpenAPI document generated
                    c.DocumentFilter<BasePathFilter>("{{{.}}}");
                    {{/basePathWithoutHost}}

                    // Include DataAnnotation attributes on Controller Action parameters as OpenAPI validation rules (e.g required, pattern, ..)
                    // Use [ValidateModelState] on Actions to actually validate it in C# as well!
                    c.OperationFilter<GeneratePathParamsValidationFilter>();
                });
{{#useNewtonsoft}}
                services
                    .AddSwaggerGenNewtonsoftSupport();
{{/useNewtonsoft}}
{{/useSwashbuckle}}
        }

        /// <summary>
        /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseDefaultFiles();
            app.UseStaticFiles();
{{#useSwashbuckle}}
            app.UseSwagger(c =>
                {
                    c.RouteTemplate = "openapi/{documentName}/openapi.json";
                })
                .UseSwaggerUI(c =>
                {
                    // set route prefix to openapi, e.g. http://localhost:8080/openapi/index.html
                    c.RoutePrefix = "openapi";
                    //TODO: Either use the SwaggerGen generated OpenAPI contract (generated from C# classes)
                    c.SwaggerEndpoint("/openapi/{{{version}}}{{^version}}v1{{/version}}/openapi.json", "{{{appName}}}{{^appName}}{{packageName}}{{/appName}}");

                    //TODO: Or alternatively use the original OpenAPI contract that's included in the static files
                    // c.SwaggerEndpoint("/openapi-original.json", "{{{appName}}}{{^appName}}{{packageName}}{{/appName}} Original");
                }){{/useSwashbuckle}};
            app.UseRouting();
            app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
        }
    }
}
